package com.hitnet.hitnet.pic;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.ThumbnailUtils;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.support.v4.util.LruCache;
import android.util.Log;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 *
 * 
 * 
 */
public class NativeImageLoader
{
	private LruCache<String, Bitmap> mMemoryCache;
	private static NativeImageLoader mInstance = new NativeImageLoader();
	private ExecutorService mImageThreadPool = Executors.newFixedThreadPool(1);
	public boolean allow = true;
	private Object lock = new Object();
	private int mStartLoadLimit;
	private int mStopLoadLimit;
	private boolean firstLoad = true;
	public void setLoadLimit(int startLoadLimit,int stopLoadLimit){
		if(startLoadLimit > stopLoadLimit){
			return;
		}
		mStartLoadLimit = startLoadLimit;
		mStopLoadLimit = stopLoadLimit;
		synchronized (lock) {
			lock.notifyAll();
		}
	}
	public void lock(){
		allow = false;
		firstLoad = false;
	}
	public void setFirst(){
		firstLoad = true;
	}
	public void unlock(){
		allow = true;
	}
	/**
	 * set cache size for loading bitmaps
	 */
//	public static HashMap<String, Boolean> mSelectMap = new HashMap<String, Boolean>();
	public static List<String> mSelectList = new ArrayList<String>();
	private NativeImageLoader()
	{
		// acquire the maximum available memory
		final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

		// set cache size
		final int cacheSize = maxMemory / 16;
		//
		mMemoryCache = new LruCache<String, Bitmap>(cacheSize)
		{

			// acquire the size of each image
			@Override
			protected int sizeOf(String key, Bitmap bitmap)
			{
				return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
			}
		};
	}

	/**
	 *
	 * 
	 * @return
	 */
	public static NativeImageLoader getInstance()
	{
		return mInstance;
	}

	/**
	 *
	 * 
	 * @param path
	 * @param mCallBack
	 * @return
	 */
	/*
	 * public Bitmap loadNativeImage(final String path, final
	 * NativeImageCallBack mCallBack){ return this.loadNativeImage(path, null,
	 * mCallBack); }
	 */

	/**
	 *
	 * 
	 * @param path
	 * @param width
	 * @param height
	 * @param mCallBack
	 * @return
	 */
	public Bitmap loadNativeImage(final int postion, final String path, final int width, final int height,
			final NativeImageCallBack mCallBack)
	{
		
		// get image from cache
		Bitmap bitmap = getBitmapFromMemCache(path);
        // return image if it's in the cache
		if(bitmap != null){
			return bitmap;
		}

		final Handler mHander = new Handler()
		{

			@Override
			public void handleMessage(Message msg)
			{
				super.handleMessage(msg);
				mCallBack.onImageLoader((Bitmap) msg.obj, path);
			}

		};

		// loading image from the disk
			mImageThreadPool.execute(new Runnable()
			{
				public void run()
				{
					if(!allow){
						synchronized (lock) {
							try {
								lock.wait();
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
						}
					}
					if (firstLoad || (postion>=mStartLoadLimit && postion<=mStopLoadLimit))
					{
						// get thumbnail
					Bitmap mBitmap = decodeThumbBitmapForFile(path, 100, 100);
					Message msg = mHander.obtainMessage();
					msg.obj = mBitmap;
					mHander.sendMessage(msg);

					// load thumbnail bitmap to cache
					addBitmapToMemoryCache(path, mBitmap);
					}
				}
			});
		
		return bitmap;

	}
	
	/**
	 *
	 * 
	 * @param path
	 * @param width
	 * @param height
	 * @param mCallBack
	 * @return
	 */
	public Bitmap loadNativeImage(final String path, final int width, final int height,
			final NativeImageCallBack mCallBack)
	{
		
		//
		Bitmap bitmap = getBitmapFromMemCache(path);
		if(bitmap != null){
			return bitmap;
		}

		final Handler mHander = new Handler()
		{

			@Override
			public void handleMessage(Message msg)
			{
				super.handleMessage(msg);
				mCallBack.onImageLoader((Bitmap) msg.obj, path);
			}

		};

		//  load images from permanent storage
			mImageThreadPool.execute(new Runnable()
			{
				public void run()
				{
					// get thumbnail
					Bitmap mBitmap = decodeThumbBitmapForFile(path, 200, 200);
					Message msg = mHander.obtainMessage();
					msg.obj = mBitmap;
					mHander.sendMessage(msg);
					// load bitmap to cache
					addBitmapToMemoryCache(path, mBitmap);
				}
			});
		return bitmap;

	}

	/**
	 *
	 * 
	 * @param key
	 * @param bitmap
	 */
	private void addBitmapToMemoryCache(String key, Bitmap bitmap)
	{
		if (getBitmapFromMemCache(key) == null && bitmap != null)
		{
			mMemoryCache.put(key, bitmap);
		}
	}

	/**
	 *
	 * 
	 * @param key
	 * @return
	 */
	private Bitmap getBitmapFromMemCache(String key)
	{
		return mMemoryCache.get(key);
	}

	/**
	 *
	 * 
	 * @param path
	 * @param viewWidth
	 * @param viewHeight
	 * @return
	 */

	// compress original image to a thumbnail
	private Bitmap decodeThumbBitmapForFile(String srcPath, int width, int height) {
		BitmapFactory.Options newOpts = new BitmapFactory.Options();
		//
		newOpts.inJustDecodeBounds = true;

		Bitmap bitmap;
		//如果是视频
		if (srcPath.endsWith("mp4")
				||srcPath.endsWith("avi")){
			bitmap = getVideoThumbnail(srcPath,width,height, MediaStore.Images.Thumbnails.MICRO_KIND);
		}else{
			bitmap = BitmapFactory.decodeFile(srcPath,newOpts);//
			newOpts.inJustDecodeBounds = false;
			int w = newOpts.outWidth;
			int h = newOpts.outHeight;
			// screen resolution
			float hh = height;// height
			float ww = width;// width

			int be = 1;//
			if (w > hh && w > ww) {//scale images in width
				be = (int) (newOpts.outWidth / ww);
			} else if (w < h && h > hh) {//scale image in height
				be = (int) (newOpts.outHeight / hh);
			}
			if (be <= 0)
				be = 1;
			newOpts.inSampleSize = be;//set the proportion of scaling
			//
			bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
		}

		return compressImage(bitmap);//compress image
	}

	/**
	 * 获取视频的缩略图
	 * 先通过ThumbnailUtils来创建一个视频的缩略图，然后再利用ThumbnailUtils来生成指定大小的缩略图。
	 * 如果想要的缩略图的宽和高都小于MICRO_KIND，则类型要使用MICRO_KIND作为kind的值，这样会节省内存。
	 * @param videoPath 视频的路径
	 * @param width 指定输出视频缩略图的宽度
	 * @param height 指定输出视频缩略图的高度度
	 * @param kind 参照MediaStore.Images.Thumbnails类中的常量MINI_KIND和MICRO_KIND。
	 *            其中，MINI_KIND: 512 x 384，MICRO_KIND: 96 x 96
	 * @return 指定大小的视频缩略图
	 */
	private Bitmap getVideoThumbnail(String videoPath, int width, int height,
									 int kind) {
		Bitmap bitmap = null;
		// 获取视频的缩略图
		bitmap = ThumbnailUtils.createVideoThumbnail(videoPath, kind);
		Log.d("choose video ", "w" + bitmap.getWidth());
		Log.d("choose video ", "h" + bitmap.getHeight());
		bitmap = ThumbnailUtils.extractThumbnail(bitmap, width, height,
				ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
		return bitmap;
	}


	private Bitmap compressImage(Bitmap image) {
		if(image == null){
			return null;
		}
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//
		int options = 100;

        // compress a image until its size is smaller that 100
		while ( baos.toByteArray().length / 1024>100) {	//
			baos.reset();//
			image.compress(Bitmap.CompressFormat.JPEG, options, baos);//
			options -= 10;//
		}
		ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//
		Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//
		return bitmap;
	}

	/**
	 *
	 * 
	 * @param options
	 * @param width
	 * @param height
	 */
    // calculate compression ratio
	private int computeScale(BitmapFactory.Options options, int viewWidth, int viewHeight)
	{
		int inSampleSize = 1;
		if (viewWidth == 0 || viewWidth == 0)
		{
			return inSampleSize;
		}
		int bitmapWidth = options.outWidth;
		int bitmapHeight = options.outHeight;

		//
		if (bitmapWidth > viewWidth || bitmapHeight > viewWidth)
		{
			int widthScale = Math.round((float) bitmapWidth / (float) viewWidth);
			int heightScale = Math.round((float) bitmapHeight / (float) viewWidth);

			// ensure no distortion
			inSampleSize = widthScale < heightScale ? widthScale : heightScale;
		}
		return inSampleSize;
	}


	/**
	 * get the amount of images
	 * @return
	 * 2014-8-12
	 */
	public static int getSelectSize(){
		return mSelectList.size();
	}

	/**
	 *
	 * 
	 */
	public interface NativeImageCallBack
	{
		/**
		 *
		 * 
		 * @param bitmap
		 * @param path
		 */
		public void onImageLoader(Bitmap bitmap, String path);
	}
}
